#pragma once

#include <vector>
#include <opencv2/opencv.hpp>

#include "utils/data/image_data.h"    // image::Image
#include "utils/file/file_handling.h" // FileExists

namespace tcv {

static const std::vector<std::string> CLASS_NAMES = {
  "person",        "bicycle",      "car",
  "motorcycle",    "airplane",     "bus",
  "train",         "truck",        "boat",
  "traffic light", "fire hydrant", "stop sign",
  "parking meter", "bench",        "bird",
  "cat",           "dog",          "horse",
  "sheep",         "cow",          "elephant",
  "bear",          "zebra",        "giraffe",
  "backpack",      "umbrella",     "handbag",
  "tie",           "suitcase",     "frisbee",
  "skis",          "snowboard",    "sports ball",
  "kite",          "baseball bat", "baseball glove",
  "skateboard",    "surfboard",    "tennis racket",
  "bottle",        "wine glass",   "cup",
  "fork",          "knife",        "spoon",
  "bowl",          "banana",       "apple",
  "sandwich",      "orange",       "broccoli",
  "carrot",        "hot dog",      "pizza",
  "donut",         "cake",         "chair",
  "couch",         "potted plant", "bed",
  "dining table",  "toilet",       "tv",
  "laptop",        "mouse",        "remote",
  "keyboard",      "cell phone",   "microwave",
  "oven",          "toaster",      "sink",
  "refrigerator",  "book",         "clock",
  "vase",          "scissors",     "teddy bear",
  "hair drier",    "toothbrush"};

struct Detection {
  float confidence;
  cv::Rect bbox;
  int class_id;
  std::string class_name;
};

/**
 * @brief 对单张图像进行读取
 *
 * @param image_path 输入图像的完整路径
 * @param im 返回OpenCV图像读取结果到结构体image::Image
 */
void read_single_image(image::Image& im, const std::string& image_path);
/**
 * @brief 对多张图像进行读取
 *
 * @param image_path 输入图像的完整路径
 * @param im 返回OpenCV图像读取结果到结构体image::Image
 */
void read_batch_images(std::vector<image::Image>& im,
                       const std::vector<std::string>& image_path);

/**
 * @brief LetterBox 对图像处理成目标大小, 不改变长宽比; 在短边补 padding;
 *
 * @param src 输入图像
 * @param dst_size 目标尺寸, 宽高一样
 * @param color padding 颜色（默认黑色）
 * @return cv::Mat 补padding后的图像
 */
cv::Mat LetterBox(const cv::Mat& src, const cv::Size& dst_size,
                  const cv::Scalar& color = cv::Scalar(0, 0, 0));

/**
 * @brief 对图像使用 CLAHE 自适应对比度增强方法
 * @param src 输入图像 BGR 格式
 * @return 增强局部对比度的图像
 */
cv::Mat ApplyCLAHE(const cv::Mat& src);

/**
 * @brief 对图像进行预处理
 * @param im 输入图像
 * @param input_shape 输入图像形状: [batch, channel, height, width]
 * @return 处理后的图像数据float数组
 */
template<typename T>
std::vector<T> PreprocessImage(const cv::Mat& image,
                               std::vector<int64_t>& input_shape);

/**
 * @brief 后处理: 过滤检测框
 * @param im 输入图像
 * @return 处理后的图像 Detection vector 数组
 */
std::vector<Detection> FilterDetections(const std::vector<float>& results,
                                        float confidence_threshold,
                                        int img_width, int img_height,
                                        int orig_width, int orig_height);

/*
 * 给图像打标签
 *
 * @param image: 输入图像
 * @param detections: Detection vector 数组
 * @return: 带标签的图像
 */
cv::Mat DrawLabels(const cv::Mat& image,
                   const std::vector<Detection>& detections);
} // namespace tcv